<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
  // TODO: 函数柯里化:
    // 把接收多个参数的函数, 变成一个接收单个参数的函数, 并返回接收余下参数且返回结果的新函数
  function curry(fn, args = []) {
    return function(){
      let rest = [...args, ...arguments];
      if (rest.length < fn.length) {
        return curry.call(this, fn, rest);
      } else {
        return fn.apply(this, rest);
      }
    }
  }

  // TODO: 复用参数
    // 例如, 用正则验证一个手机号
  const phoneReg = /^1[3-9]\d{9}$/;

  function checkPhone(reg, phone) {
      return reg.test(phone);
  }

  console.log(checkPhone(phoneReg, 19956526362));

  // 柯里化
  const curryCheckPhone = curry(checkPhone)(phoneReg);  // 这样我们就复用了验证手机的正则，这就是复用参数，或者说是固定参数
  curryCheckPhone(19956526362);
  curryCheckPhone(16956526362);


  // TODO: 提前返回、延迟执行
    // 例如, 需要对一个正确的手机号做一系列不同步的操作（同步的话就没有意义了）
  function doSomething1(reg, phone, callback) {
    reg.test(phone) && callback();
  }

  function doSomething2(reg, phone, callback) {
    reg.test(phone) && callback();
  }

  doSomething1(phoneReg, 19956526362, function callback1(){});
  doSomething2(phoneReg, 19956526362, function callback2(){});
  // 既然是对同一个号码做判断, 我们当然可以先将判断结果保存下来, 这样就不用每次都做判断了
  function doSomething(reg, phone, callback) {
    reg.test(phone) && callback();
  }

  const curryDoSomething = curry(doSomething)(phoneReg)(19956526362);  // 这里就是提前返回电话号码是否正确了
  curryDoSomething(function callback1(){});                                         // 这里就是延迟执行
  curryDoSomething(function callback2(){});

  // TODO: 反柯里化其实就是柯里化的逆过程, 目的就是扩大函数的适用范围
  // 比如数组的 push 方法只能用于数组, 通过反柯里化提取 push 函数, 让它也适用于 Object 对象
  Function.prototype.uncurry = function () {
    let prototypeFn = this;
    return function () {
      let obj = Array.prototype.shift.call(arguments);
      prototypeFn.apply(obj, arguments);
    }
  }

  const obj = {
    name: 'test'
  }

  const pushUncurry = Array.prototype.push.uncurry();
  pushUncurry(obj, '123')

  </script>
</body>
</html>